package com.pap.gateway.config.security.core;

import com.pap.base.constant.JWTConstants;
import com.pap.gateway.config.security.core.exception.PapEmptyJwtException;
import org.springframework.context.annotation.Bean;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.web.server.context.ServerSecurityContextRepository;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * Security 自定义认证，从 header 获取数据进行 数据维护
 */
@Component
public class PapSecurityContextRepository implements ServerSecurityContextRepository {

    @Bean
    public PapAuthenticationManager authenticationManager() {
        return new PapAuthenticationManager();
    }

    @Override
    public Mono<Void> save(ServerWebExchange serverWebExchange, SecurityContext securityContext) {
        return Mono.empty();
    }

    @Override
    public Mono<SecurityContext> load(ServerWebExchange serverWebExchange) {
        ServerHttpRequest request = serverWebExchange.getRequest();

        // TODO  根据需求判断 pap-gateway 是否需要进行监控，如需进行监控，则需要注意如下几点：
        //      1、bootstrap.properties 增加节点：management.endpoints.web.base-path=/_gateway/_actuator ， 确保监控路径在指定的节点下(不会冲突)；
        //      2、bootstrap.properties 增加节点：spring.cloud.nacos.discovery.metadata.management.context-path=/_gateway/_actuator ， 确保spring-cloud-admin 中提交的监控路径正确；
        //      3、WebSecurityConfig 类文件，需要增加过滤， 将上述的 /_gateway/_actuator  地址加入隔离：  .pathMatchers("/_gateway/_actuator/**").permitAll() ；
        //      4、下述注释的代码部分进行放开，判断如果是以 /_gateway/_actuator 开头的请求，这说明是针对 pap-gateway 进行的监控，则放开请求，返回一个空的   SecurityContext 对象；
//        if(request.getPath().toString().startsWith("/_gateway/_actuator")) {
//            return Mono.just(new SecurityContext() {
//                @Override
//                public Authentication getAuthentication() {
//                    return null;
//                }
//
//                @Override
//                public void setAuthentication(Authentication authentication) {
//
//                }
//            });
//        }

        String authHeader = request.getHeaders().getFirst(JWTConstants.TOKEN_HEADER);

        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String authToken = authHeader.substring(7);
            Authentication auth = null;
            auth = new UsernamePasswordAuthenticationToken(authToken, authToken);
            Mono<SecurityContext> securityContextMono = authenticationManager().authenticate(auth).map(SecurityContextImpl::new);
            return  securityContextMono;
        } else {
            return Mono.error(new PapEmptyJwtException(""));
        }
    }
}